/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2020年10月5日
 */
package com.massyframework.beanskin.service.crypto;

import java.util.Base64;

/**
 * 封装rsa数字签名、验签、加密、解密等实现
 * 
 * @author huangkh
 *
 */
public interface RSAService {

	/**
     * 使用私钥对<code>content</code>进行加密
     * @param content {@link byte}数组，要加密的内容
     * @param privateKey {@link String}, 私钥
     * @return {@link byte}数组, 密文
     * @throws {@link CryptoException},加解密时发生的例外
     */
    byte[] encryptWithPrivateKey(byte[] content, String privateKey)
            throws CryptoException;

    /**
     * 使用公钥对<code>content</code>进行加密
     * @param content {@link byte}数组，要加密的内容
     * @param publicKey {@link String}, 公钥
     * @return {@link byte}数组, 密文
     * @throws {@link CryptoException},加解密时发生的例外
     */
    byte[] encryptWithPublicKey(byte[] content, String publicKey)
            throws CryptoException;

    /**
     * 使用私钥对<code>content</code>进行加密
     * @param content {@link String}，要加密的内容
     * @param privateKey {@link String}, 私钥
     * @return {@link String}, 密文
     * @throws {@link CryptoException},加解密时发生的例外
     */
    default String encryptStringWithPrivateKey(String content, String privateKey) throws CryptoException {
    	try {
	        byte[] encrypted = this.encryptWithPrivateKey(content.getBytes("utf-8"), privateKey);
	        return Base64.getEncoder().encodeToString(encrypted);
    	}catch(CryptoException e) {
    		throw e;
    	}catch(Exception e) {
    		throw new CryptoException(e.getMessage(), e);
    	}
    }

    /**
     * 使用公钥对<code>content</code>进行加密
     * <p>
     * 公钥可以使用PKCS8格式的，或者x509证书格式的公钥, 其他公钥格式不支持。
     * <pre>
     * PKCS8格式公钥，头部为-----BEGIN PUBLIC KEY-----
     * X509证书格式，头部为-----BEGIN CERTIFICATE-----
     * </pre>
     * @param content {@link String}，要加密的内容
     * @param publicKey {@link String}, 公钥
     * @return {@link String}, 密文
     * @throws {@link CryptoException},加解密时发生的例外
     */
    default String encryptStringWithPublicKey(String content, String publicKey) throws CryptoException {
    	try {
	        byte[] encrypted = this.encryptWithPublicKey(content.getBytes("utf-8"), publicKey);
	        return Base64.getEncoder().encodeToString(encrypted);
    	}catch(CryptoException e) {
    		throw e;
    	}catch(Exception e) {
    		throw new CryptoException(e.getMessage(), e);
    	}
    }

    /**
     * 使用私钥对<code>encrypted</code>进行解密.<br>
     * 本方法和{@link #encryptWithPublicKey(byte[], String)}相对应使用。
     * @param encrypted {@link byte}数组，加密的内容
     * @param privateKey {@link String}, 私钥
     * @return {@link byte}数组, 解密后的数据
     * @throws {@link CryptoException},加解密时发生的例外
     */
    byte[] decryptWithPrivateKey(byte[] encrypted, String privateKey)
            throws CryptoException;

    /**
     * 使用公钥对<code>encrypted</code>进行解密.<br>
     * 本方法和{@link #encryptWithPrivateKey(byte[], String)}相对应使用。
     * 
     * <p>
     * 公钥可以使用PKCS8格式的，或者x509证书格式的公钥, 其他公钥格式不支持。
     * <pre>
     * PKCS8格式公钥，头部为-----BEGIN PUBLIC KEY-----
     * X509证书格式，头部为-----BEGIN CERTIFICATE-----
     * </pre>
     * @param encrypted {@link byte}数组，加密的内容
     * @param publicKey {@link String}, 私钥
     * @return {@link byte}数组, 解密后的数据
     * @throws {@link CryptoException},加解密时发生的例外
     */
    byte[] decryptWithPublicKey(byte[] encrypted, String publicKey)
            throws CryptoException;

    /**
     * 使用私钥对<code>encrypted</code>进行解密, 并返回解密后的明文
     * @param encryptedText {@link String}, 密文
     * @param privateKey {@link String}, 私钥
     * @return {@link String}，解密后的明文
     * @throws {@link CryptoException},加解密时发生的例外
     */
    default String decryptStringWithPrivateKey(String encryptedText, String privateKey) throws CryptoException {
    	try {
	        byte[] encrypted = Base64.getDecoder().decode(encryptedText);
	        byte[] result = this.decryptWithPrivateKey(encrypted, privateKey);
	        return new String(result, "utf-8");
    	}catch(CryptoException e) {
    		throw e;
    	}catch(Exception e) {
    		throw new CryptoException(e.getMessage(), e);
    	}
    }

    /**
     * 使用公钥对<code>encrypted</code>进行解密, 并返回解密后的明文
     * <p>
     * 公钥可以使用PKCS8格式的，或者x509证书格式的公钥, 其他公钥格式不支持。
     * <pre>
     * PKCS8格式公钥，头部为-----BEGIN PUBLIC KEY-----
     * X509证书格式，头部为-----BEGIN CERTIFICATE-----
     * </pre>
     * @param encryptedText {@link String}, 密文
     * @param publicKey {@link String}, 公钥
     * @return {@link String}，解密后的明文
     * @throws {@link CryptoException},加解密时发生的例外
     */
    default String decryptStringWithPublicKey(String encryptedText, String publicKey) throws CryptoException {
    	try {
	        byte[] encrypted = Base64.getDecoder().decode(encryptedText);
	        byte[] result = this.decryptWithPublicKey(encrypted, publicKey);
	        return new String(result, "utf-8");
    	}catch(CryptoException e) {
    		throw e;
    	}catch(Exception e) {
    		throw new CryptoException(e.getMessage(), e);
    	}
    }

    /**
     * 签名
     * @param content {@link byte}数组，签名的内容
     * @param privateKey {@link String}, 签名的私钥字符串
     * @return {@link String}, 签名生成的数据, Base64编码
     * @throws {@link CryptoException},加解密时发生的例外
     */
    String sign(byte[] content, String privateKey)
            throws CryptoException;

    /**
     * 签名
     * @param content {@link String}, 签名的内容
     * @param privateKey {@link String}, 签名的私钥字符串
     * @return {@link String}, 签名生成的数据
     * @throws Exception 未预期的例外
     * @throws {@link CryptoException},加解密时发生的例外
     */
    default String sign(String content, String privateKey)
            throws CryptoException {
    	try {
	        byte[] data = content.getBytes("utf-8");
	        return this.sign(data, privateKey);
    	}catch(CryptoException e) {
    		throw e;
    	}catch(Exception e) {
    		throw new CryptoException(e.getMessage(), e);
    	}
    }

    /**
     * 验证签名
     * <p>
     * 公钥可以使用PKCS8格式的，或者x509证书格式的公钥, 其他公钥格式不支持。
     * <pre>
     * PKCS8格式公钥，头部为-----BEGIN PUBLIC KEY-----
     * X509证书格式，头部为-----BEGIN CERTIFICATE-----
     * </pre>
     * @param content {@link byte}数组，签名的内容
     * @param signedData {@link String}， 签名生成的数据, Base64编码
     * @param publicKey {@link String}, 验证签名的公钥字符串
     * @return {@link boolean}, 签名验证是否成功，返回<code>true</code>表示成功
     * @throws {@link CryptoException},加解密时发生的例外
     */
    boolean verify(byte[] content, String signedData, String publicKey)
            throws CryptoException;

    /**
     * 验证签名
     * <p>
     * 公钥可以使用PKCS8格式的，或者x509证书格式的公钥, 其他公钥格式不支持。
     * <pre>
     * PKCS8格式公钥，头部为-----BEGIN PUBLIC KEY-----
     * X509证书格式，头部为-----BEGIN CERTIFICATE-----
     * </pre>
     * @param content {@link String}，签名的内容
     * @param signedData {@link String}， 签名生成的数据, Base64编码
     * @param publicKey {@link String}, 验证签名的公钥字符串
     * @return {@link boolean}, 签名验证是否成功，返回<code>true</code>表示成功
     * @throws {@link CryptoException},加解密时发生的例外
     */
    default boolean verify(String content, String signedData, String publicKey)
            throws CryptoException {
    	try {
    		byte[] data = content.getBytes("utf-8");
    		return this.verify(data, signedData, publicKey);
    	}catch(CryptoException e) {
    		throw e;
    	}catch(Exception e) {
    		throw new CryptoException(e.getMessage(), e);
    	}
    }
}
